package com.zhigh.project.tools;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;

/**
 * Java 流聚合处理
 */
public interface CollectorImpls {

    static <ID, T> Collector<T, Map<ID, T>, Map<ID, T>> mappedById(Function<T, ID> idExtractor) {
        return new CollectorImpl<>(
                HashMap::new,
                (r, t) -> r.put(idExtractor.apply(t), t),
                (left, right) -> {
                    left.putAll(right);
                    return left;
                },
                Collections.singleton(Collector.Characteristics.IDENTITY_FINISH)
        );
    }

    static <V> Collector<Map.Entry<String, V>, Map<String, V>, Map<String, V>> keyAddPrefix(String prefix) {
        return new CollectorImpl<>(
                HashMap::new,
                (r, entry) -> r.put(prefix + entry.getKey(), entry.getValue()),
                (left, right) -> {
                    left.putAll(right);
                    return left;
                },
                Collections.singleton(Collector.Characteristics.IDENTITY_FINISH)
        );
    }


    @SuppressWarnings("unchecked")
    class CollectorImpl<T, A, R> implements Collector<T, A, R> {

        private final Supplier<A> supplier;
        private final BiConsumer<A, T> accumulator;
        private final BinaryOperator<A> combiner;
        private final Function<A, R> finisher;
        private final Set<Characteristics> characteristics;

        CollectorImpl(Supplier<A> supplier,
                      BiConsumer<A, T> accumulator,
                      BinaryOperator<A> combiner,
                      Function<A, R> finisher,
                      Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.combiner = combiner;
            this.finisher = finisher;
            this.characteristics = characteristics;
        }


        public CollectorImpl(
                Supplier<A> supplier, BiConsumer<A, T>
                accumulator, BinaryOperator<A> combiner,
                Set<Characteristics> characteristics) {
            this.supplier = supplier;
            this.accumulator = accumulator;
            this.finisher = a -> (R) a;
            this.combiner = combiner;
            this.characteristics = characteristics;
        }

        @Override
        public Supplier<A> supplier() {
            return supplier;
        }

        @Override
        public BiConsumer<A, T> accumulator() {
            return accumulator;
        }

        @Override
        public BinaryOperator<A> combiner() {
            return combiner;
        }

        @Override
        public Function<A, R> finisher() {
            return finisher;
        }

        @Override
        public Set<Characteristics> characteristics() {
            return characteristics;
        }
    }

}

